Android 一些有意思的命令小工具 —— lshal
更新日期:
android 自带了很多 cmds 的小工具,都挺用有的,也有些比较有意思。这里介绍的是 lshal 这个工具。说之前先把相关源码位置说下(10.0 的):
|
|
作用
之前的文章介绍的:Android 一些有意思的命令小工具 —— dumpsys 和 Android 一些有意思的命令小工具 —— service 。service 的作用在于列出 ServiceManager 中已经注册了的服务,并且可以调用服务的接口来进行调试。而 dumpsys 则是调用指定服务的 dump 接口打印服务中的一些状态,用于调试。
上面这些工具都是针对系统的 Binder 服务的。从 Android 8.0 开始,Android 在 HAL 层引入了 HIDL 的设计。将 hal 层模块变成类似 Binder 的结构,通过统一的接口,来解耦 hal 层(详细信息可以去看官网的介绍:HIDL)。这个就相当于是在 hal 层也跑一些系统服务,只不过为了安全考虑,Android 把 hal 层的服务和 java 层的 SystemService 区分开了,hal 层使用的 binder 设备是 /dev/hwbinder(java 层的是 /dev/binder),hal 层的是 hwservicemanager(java 层的是 ServiceManager,不过这2个进程代码是一样的,就是启动的时候传入参数不一样,使用的 binder 设备节点不一样而已)。
lshal 就是针对 hidl 的 service 和 dumpsys 的集合。当然它的功能不止这些,看官方介绍,还能生成兼容性矩阵描述信息之类的(官方的介绍:LSHAL)。但是我们这里主要是介绍类似 service 和 dumpsys 的功能:
list
list 命令会列出所有的 HIDL 服务(不加 list 也行,默认空参数就是 list 命令):
|
|
这里分了几个类别把所有的 hidl 都列了出来,从源码里面可以看得到所有类别,对应类别没有的就没列:
|
|
(1). 绑定式HAL: 使用 hwbinder IPC 通讯实现的 hal。mServicesTable 属于这一类。这也是 8.0 之后的新 hal 架构,大多数的 hal 是这种类型(上面我没贴完整所有的 hidl)。
(2). 直通式HAL: 又分2种:一种是以 HIDL 分装的传统的 hal,这个是 mImplementationsTable 类别;另一种就是完全传统的 hal,这个是 mPassthroughRefTable 类别。这2类的比较少,应该是要慢慢淘汰掉的。
还有剩下2个类别:mManifestHalsTable 好像是单纯的 VINTF manifest 文件,mLazyHalsTable 好像是使用了 HIDL 框架的但是没在 hwservicemanager 中注册的和没有真正实现的。这2类目前都没有,先暂时不管先。详细的 hal 分类可以看官网说明:HAL 类型。
下面列出来每一列的含义:
(1). VINTF: 这个叫供应商接口(Vendor Interface),主要是用于描述 hal 的接口信息的,现在 hal interface 也分版本了,就涉及到兼容性。具体的可以看官网说明:供应商接口对象 。列出的一些 FM、DC、FC 我暂时还没去搞明白是啥意思,以后再说。
(2). R: 这个 R 我也暂时还没去搞明白是啥意思,以后再说。
(3). Interface: 这个就是 hidl 向 hwservicemanager 注册服务的接口名字,client 需要通过名字来获取对应的服务对象。这个和 java 的 SystemService 是类似的。例如说 ActivityManager 的接口名字叫 activity,WindowManager 的叫 window,只不过 hidl 的名字普遍比较长(包名)还带版本。
(4). Thread: 应该是 hidl 中运行的服务线程数量,但是有2个,我猜测应该第一个是正在响应服务调用的,后面那个应该是线程池的数量。具体我还没去核对源码,后面再说。
(5). Use: 空的,好像没啥用
(6). Server: 服务运行的进程 pid
(7). Clients: 连接的 client 的进程的 pid
lshal 列出的信息比 service 多很多。虽然有些含义目前还没明白是什么意思,但是用来确认 hal 服务有没有在运行已经足够了。
debug
lshal debug xx :
(待补充)
源码分析
lshal 的源码目录结构如下:
|
|
lshal 是一个 bin 文件,程序入口在 Lshal.cpp 的 mian 函数里面。命令处理的方式采用了面向对象的设计思想:可以看到源码目录下有下面几个文件:
|
|
Command 是基类,定义了命令的基本接口,Help、List、Debug 分别实现了 “help”, “list”, “debug” 命令。现在连小工具都采用 c++ 面向对象了,am 命令也是这样了,以前还都是 c ,面向结构的。在 Lshal.cpp 里面有讲这些命令的对象加入到命令列表里面:
|
|
通过 Command 的名字来匹配要执行的命令:
|
|
ListCommand
这个源码比较复杂(获取的信息很多,所以列出的信息也多),暂时没分析。
DebugCommand
debug 命令的调用流程:
|
|
debug 命令最后是调用到了指定 hidl 的 debug 接口,debug 这个接口是 hidl 基类里面定义的,可以实现,也可以不实现:
|
|
这个是由 hidl 的接口定义文件 .hal 自动生成的,生成的文件在: out/.intermediates/hardware/interfaces/xx/xx_genc++_headers/gen/xx/xx.h。和 aidl 类似,都是由一个工具在编译的时候自动生成源码(aidl 可以参看以前的分析文章:Android Binder 分析——懒人的工具(AIDL))。
例如说我们可以在 hidl 的 debug 接口里面实现打印一些关键变量信息(就变成了 dumpsys),它还可以接收参数,我们也可以用来做一些调试接口(dumpsys 也可以接受参数,但是 lshal 没法自由的直接调用所有接口,和 service 的 call 命令还是有点区别)。
HelpCommand
这个很简单了,就是简单的打印帮助信息,不分析了。
总结
我在接触 hidl 的时候,就在想有没有类似 SS 的 dumpsys 和 service 命令,然后看官方介绍,还真的有。这个工具在调试 hidl 还是挺好用的。